home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
ASSEMBLE
/
3809.ZIP
/
TBONES07.ZIP
/
TSRBONES.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-01-20
|
38KB
|
794 lines
;************************
PAGE 55,132 ;Format .LST listing at 55 lines by 132 columns.
TITLE TSRBONES Version 0.1 Jan 20 91 Robert Curtis Davis
SUBTTL Introduction
;**************************************************************************
;
; TSRBONES.ASM Version 0.1 Jan 20 91
; A part of the TBONES software package.
;
; Copyright (C) 1990, 1991 by Robert Curtis Davis,
; All Rights Reserved.
;
; DESCRIPTION:
; ASM Program template for Terminate-and-Stay-Resident (TSR) programs
; that are activated by a specified HotKey WHEN DOS IS NOT
; BUSY (the InDOS Flag AND the DOS Critical Error Flag are zero)
; flag), OR WHEN DOS IS AT "BUSY IDLE" (when INT28h is called),
; AND WHEN NO HARDWARE INTERRUPT IRQ0-IRQ7 IS BEING HANDLED.
; This avoids problems of interfering with hardware interrupt
; handling and with DOS non-reentrancy; and allows DOS function
; calls above 0Ch to be used in the TSR routine. The TSR's code
; prevents multiple installations. Also checks DOS version and
; requires DOS Version 2 or later before installation is
; permitted.
;
; PURPOSE:
; Provides a skeletal framework program as a starting point in the
; design of your own HotKey TSRs which use DOS function calls, and
; for which a single installation is desired.
;
; E-mail address:
; Internet: sonny@trantor.harris-atd.com
;
; US Mail address:
; 430 Bahama Drive
; Indialantic, FL 32903
;
;**************************************************************************
;
; Special thanks to Roy Silvernail, whose persistent hacking (in the best
; sense of that word) and E-mail exchanges over the holiday season in
; December 1990, rooted out TBONES incompatibilities with Borland's TASM v.1.0.
;
;**************************************************************************
;
; Special thanks to Anto Prijosoesilo and Richard Brittain for E-mail
; exchanges which helped solve detailed problems with the implementation of
; the "Pseudo-Environment" idea.
;
;**************************************************************************
;
; Special thanks to David Kirschbaum, whose Toad Hall Tweaks significantly
; improved an early version of the TBONES Assembly Language code:
;
;v0.01 Toad Hall Tweak, 25 Nov 90
;**************************************************************************
SUBTTL Code Segment
PAGE
;**************************************************************************
;
CodeSeg segment
assume cs:CodeSeg,ds:CodeSeg
BeginDump EQU $ ;Roy Silvernail - Keep TASM 1.0 happy
;when computing # resident paragraphs.
;
org 2CH ;v0.01 ORG in PSP to pick up the
envseg label word ;v0.01 Environment Segment.
;
org 100h ;ORG for all COM programs.
;
Entry PROC NEAR ;v0.01
jmp TSRinit ;Jump over resident portion and
;initialize things and make code
;between Entry: and TSRinit: resident.
;
; Old Interrupt Vectors are stored here during TSR initialization:
oldint09 dd ? ;Keyboard Hardware Interrupt.
oldint13 dd ? ;Disk BIOS Interrupt.
oldint16 dd ? ;Keyboard BIOS Interrupt.
oldint28 dd ? ;DOS Idle Interrupt.
;
; For this HotKey TSR Template, specify Keyboard Interrupt 09h as the Hook:
HOOK09 equ 09h ;Hooked Interrupt 09h.
; Int 13h is used to set a flag to prevent TSR trigger while disk active:
HOOK13 equ 13h ;Hooked Interrupt 13h.
; Int 16h is hooked solely to provide way to check for prior TSR installation.
HOOK16 equ 16h ;Hooked Interrupt 16h.
; We also have to hook Interrupt 28h to check for "DOS idle":
HOOK28 equ 28h ;Hooked Interrupt 28h.
;
bellgate db 0 ;Gate closed (=1) when in Bell routine.
;Gate open (=0) when not in Bell routine.
; Below:
; EQUates related to the Intel 8259A Programmable Interrupt Controller (PIC)
; chip. Hardware Interrupts IRQ0 through IRQ7 are controlled by the PIC.
;
; To really understand the nitty-gritty details of this stuff,
; you have to study the Intel Specification data for the 8259A PIC chip.
; These EQUates are used in this TSR to examine the PIC chip's In Service
; Register (ISR) to be sure that the TSR is not interrupting one of
; the hardware interrupt service routines. The reason for not wanting to
; interrupt these hardware interrupt service routines is that they are
; often time-critical and can be compromised by intruding on them with
; our TSR (for example, a hardware COM port interrupt-driven comm
; program might lose bytes on a modem transfer if we bull our way in and
; steal the CPU away from the comm program's service routine):
PICPORT EQU 20h ;I/O Port for the 8259A PIC chip.
ISRREQ EQU 00001011B ;This is a byte defining the
;Operation Control Word 3 (OCW3) to
;output on port 20h to make the PIC
;chip's In Service Register available
;for reading by the CPU on the
;next IN 20h command.
;
; EQUs defining Key Flag weights in the Key Flag Byte:
RSHIFT equ 00000001B ;Right Shift Key Flag weight.
LSHIFT equ 00000010B ;Left Shift Key Flag weight.
CTRL equ 00000100B ;Ctrl Key Flag weight.
ALT equ 00001000B ;Alt Key Flag weight.
;SCROLL equ 00010000B ;Scroll Lock Key Flag weight.
;NUM equ 00100000B ;Num Lock Key Flag weight.
;CAPS equ 01000000B ;Caps Lock Key Flag weight.
INSRT equ 10000000B ;Ins Key Flag weight.
;
LockKeyMask equ 10001111B ;For masking out Scroll, Caps,
;and Num Lock bits in KeyFlags.
;
; Pointer to "DOS busy" (InDOS) flag (loaded during TSR initialization):
indosptr dd ?
;
; Pointer to "Critical Error" (CritErr) flag (loaded at TSR initialization):
criterrptr dd ?
;
; Pointer to "Print Screen" busy (PrtScrn) flag
prtscrn dd 00500000h
;
; hotkeyflag used to signal HotKey pressed to "DOS idle" Interrupt 28h:
hotkeyflag db 0 ;hotkeyflag initially zero.
;
; diskflag used to prevent TSR trigger during time-critical Disk operations:
diskflag db 0 ;diskflag initially zero.
;*************************************************************************
; Your HotKey is specified here:
; (This sample HotKey is set for Ctrl-Alt-B)
;
; Specify TSR's HotKey Shift Keys:
KEYFLAGBYTE equ CTRL+ALT ;HotKey Flags
;
; Specify TSR's HotKey Scan Code:
HOTKEY equ 30h ;'B' (for Bones) key
;
;*************************************************************************
; Specify TSR's signature words:
TSRsigA equ 'TS' ;'TSRBONES' Signature
TSRsigB equ 'RB'
TSRsigC equ 'ON'
TSRsigD equ 'ES'
;*************************************************************************
Entry ENDP ;v0.01
;
;*************************************************************************
SUBTTL User-supplied TSR Routine
PAGE
;*************************************************************************
ROUTINE PROC NEAR
;*************************************************************************
; Code for your HotKey-triggered TSR routine GOES HERE:
; ( Here, a dummy routine has been placed which simply rings the
; terminal Bell whenever the TSR is triggered. )
;
; Announce this dummy TSR's trigger by a Bell signal:
;
Enter:
mov al,07h ;al = ASCII Bell.
mov bh,0 ;Video page.
mov cx,1 ;No. of bytes to write.
mov ah,0Eh ;BIOS Int10,OEh=TTY Screen.
Int 10h ;Write ASCII Bell to screen.
;
Exit:
ret ;Return from TSR routine.
;
ROUTINE endp
;
; End of your HotKeyed TSR routine.
;***************************************************************************
SUBTTL Hooked Interrupts
PAGE
;***************************************************************************
;
NewInt09 PROC FAR ;v0.01
;
; The following three instructions often are said to "simulate an interrupt"
; that calls the PRIOR interrupt handler routine and then the prior interrupt
; handler's IRET instruction pops the flags and returns here to the point
; after the following CALL instruction.
; The reason for "simulating the interrupt" here is to give prior (and
; presumably more time-critical) handlers a shot at processing this interrupt
; before we process with this TSR's code.
;
pushf ;Push flags as a true interrupt would.
cli ;Be sure interrupts are disabled.
call CS:oldint09 ;Call FAR PTR address of old interrupt
; ; handler routine.
;
;
push ax ;Prepare to check for Hotkey.
push bx ;Save all registers (DS is already pushed).
push cx
push dx
push si
push di
push bp
push ds
push es
;
push CS ;Set up data segment
pop DS ;register to point to code segment.
;
ASSUME DS:CodeSeg ;v0.01
;
; Determine if the current Keyboard Interrupt (Int09h) occurred
; because this TSR's HotKey was pressed:
in al,60h ;Get current Key Scan Code.
cmp al,HOTKEY ;Is it HotKey's Scan Code?
jne Exit09 ;Exit if not.
mov ah,02h ;Int16h,Fcn02h:GetKEYFLAGBYTE.
Int 16h ;Return Key Flag Byte in al.
and al,LockKeyMask ;Mask out Num, Caps, Scroll Lock bits.
cmp al,KEYFLAGBYTE ;Are the HotKey Flags active ?
jne Exit09 ;Exit if not.
;
; At this point, Hotkey is known to have been pressed. First, purge
; the DOS Keyboard type-ahead buffer of the hot key(s) so they won't
; be passed on to DOS:
;
ClrKbdBuf: ;Clear Keyboard buffer:
mov ah,01h ;Get Keyboard buffer status
int 16h ;via BIOS Interrupt 16h.
jz BufClr ;Jump if buffer empty.
mov ah,00h ;Get key from buffer (to purge it)
int 16h ;via BIOS Interrupt 16h.
jmp ClrKbdBuf ;Loop back to purge another key.
BufClr:
;
; We shall allow other interrupts to occur during our TSR ROUTINE.
; If we didn't allow other interrupts (through the STI instruction),
; we could lock out time-critical interrupts from access to the CPU during
; our TSR routine. However, by allowing interrupts during our routine, we
; have an increased responsibility to make sure critical portions of our
; own code is not re-entered. (The "bellgate" stuff below is an example
; of a measure necessary to keep us from re-entering our own TSR's code).
; What we really want to do by allowing interrupts is to make the CPU avail-
; able to OTHER critical interrupt service routines WITHOUT swarming all over
; ourselves through multiple detections of our own HotKey.
; This "gate" technique is a good one to keep in
; mind whenever you have a code region in an interrupt handler
; that needs to be protected from re-entry:
;
cmp bellgate,0 ;Is it clear to re-enter Hotkey code?
jne BusyExit09 ;Exit if not,
mov bellgate,1 ;Else, close gate and proceed.
;
CLI ;DISABLE INTERRUPTS
; Now we will check to be sure that no time-critical hardware interrupt
; handling is underway. We do this by querying the Intel 8259A Program-
; mable Interrupt Controller (PIC) chip's In Service Register (ISR) and
; testing it to see that it is zero (i.e., nothing being serviced).
;
HotKeyPressed:
mov al,ISRREQ ;al=PIC's OCW3 to ask for ISR Register.
out PICPORT,al ;Tell PIC to get ISR ready for reading.
jmp Dally ;Give PIC time to make ISR available.
Dally: in al,PICPORT ;Fetch the ISR Register from PIC.
or al,al ;Activate processor flags.
jnz SetFlag ;If al not zero, go set flag.
;
; At this point, HotKey is known to be pressed AND NO hardware interrupt
; is being serviced. BUT is InDOS flag zero, indicating that DOS is
; not busy and therefore can safely be entered? This will now be
; checked:
;
HotKeyNoHWI:
les bx,indosptr ;es:bx = pointer to InDOS flag
mov al,es:[bx] ;al = InDOS flag.
or al,al ;Activate processor flags.
jnz SetFlag ;Jump if InDOS not zero.
;
; Include a check on Critical Error flag. Don't trigger the TSR if
; DOS is in the middle of handling a Critical Error:
;
les bx,criterrptr ;es:bx = pointer to CritErr flag.
mov al,es:[bx] ;al = CritErr flag.
;
; Also, don't trigger the TSR if time-critical Disk access is underway:
; Normally, this Disk check would not be necessary since the
; InDOS flag would not be clear during Disk accesses, BUT some
; software will bypass DOS and go directly to the BIOS Int13
; Interrupt for Disk access. Therefore, to be safe, we HAVE to
; be sure Int13 has not been entered and is not in the process
; of performing time-critical Disk stuff when we hit the TSR
; HotKey. Many TSRs don't even check this. They just depend
; upon users not to hit the HotKey during Disk access. That seems
; terribly risky to me:
;
or al,diskflag ;al = CritErr | diskflag
; (| => Logical OR).
jnz Exit09 ;If al not zero, try again later.
;
; Also, don't trigger the TSR if a PrtScrn is in progress:
; (Is this really necessary? I don't think TSR will trigger during PrtSc)
les bx,prtscrn ;ES:bx = pointer to PrtScrn busy flag.
cmp BYTE PTR es:[bx],1 ;Is PrtScrn in progress?
je Exit09 ;If so, try again later.
;
STI ;Allow other interrupts in our TSR.
;
call ROUTINE ;All is clear!, so call routine.
mov hotkeyflag,0 ;Be sure HotKey flag is reset.
jmp SHORT Exit09 ;Exit after TSR routine.
;
SetFlag:
mov hotkeyflag,1 ;Set HotKey Flag for use by Int28h.
;
Exit09:
mov CS:bellgate,0 ;Open gate allowing new HotKey detect.
BusyExit09:
pop es ;Restore all registers
pop ds
ASSUME DS:NOTHING ;v0.01
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
;
;
; Return from this TSR's Keyboard Interrupt 09h handler routine:
iret
;
NewInt09 ENDP ;v0.01
;
;*************************************************************************
PAGE
;*************************************************************************
NewInt13 PROC FAR ;We hook Int13h only for purpose
;of setting a flag to prevent our
;TSR from triggering during time-
;critical Disk accesses.
mov CS:diskflag,1 ;Set flag to show Disk access.
;
pushf ;Invoke prior Int13 handler
cli ;(be sure interrupts disabled)
call CS:oldint13 ;by simulating an interrupt.
;
mov CS:diskflag,0 ;Clear flag to show Disk finished.
;
; The following RET 2 bumps the SP register up by 2 bytes to effectively
; take the flags off the stack (where they were put by the invoking
; INT 13h) WITHOUT popping them off and ruining the meaningful flags
; left in the Flags register by the original DOS INT13 handler (the
; DOS INT13 handler also returns via a RET 2 to keep from ruining the
; Flags that the handler has painstakingly prepared for communicating
; back to the calling program). The effect on the stack pointer, SP, is
; exactly the same as with the more usual IRET. It is just that the Flags
; in the Flag register are preserved at the values the handler placed
; and wanted there.
;
RET 2 ;Return from interrupt while
;preserving flags.
;
NewInt13 ENDP
;*************************************************************************
PAGE
;*************************************************************************
NewInt16 PROC FAR ;v0.01
;
push ds ;Entry for New Int. Handler.
; ;Save required registers.
;
push CS ;Set data seg v0.01
pop DS ;to our CodeSeg v0.01
ASSUME DS:CodeSeg ;v0.01
;
; This next portion of code provides back to the non-resident
; TSR installation code a check on whether the TSR has already been installed.
; It does this through the following technique:
; Check to see if the ax, bx, cx, dx registers are loaded with this
; TSR's signature words. Since all TSR ax signature words are chosen
; so as NOT to match any allowed DOS Int16h Function in ah, ALL
; standard DOS Int16h calls will exit from this sequence of compares
; at the first JNE instruction below and will ultimately be processed
; by the standard DOS Int16h handler.
; The ONLY place where all the registers are loaded with THIS TSR's
; signature words and then Int16h called is IN THE INITIALIZATION CODE
; AT THE END OF THIS TSR. Given that all the signature words are matched
; in the four comparisons below, we need to signal back to the
; invoking TSR initialization code by setting the data registers to
; values that NEVER would be returned by the standard DOS Int16h handler,
; and that therefore could ONLY have come from this previously-installed
; TSR's Int16h handler code. The TSR installation code will then take
; the return of these unique register values as the indication that
; this TSR has already been installed.
;
cmp ax,TSRsigA ;Is ax = TSR signature word A?
jne Exit16 ;No, let regular Int16 handle this.
cmp bx,TSRsigB ;Is bx = TSR signature word B?
jne Exit16 ;No, let regular Int16 handle this.
cmp cx,TSRsigC ;Is cx = TSR signature word C?
jne Exit16 ;No, let regular Int16 handle this.
cmp dx,TSRsigD ;Is dx = TSR signature word D?
jne Exit16 ;No, let regular Int16 handle this.
;
; The ONLY way you ever get to here is by having called Int16h with the
; ax, bx, cx, dx registers loaded with this TSR's signature words. This
; only occurs in the TSR initialization routine. Therefore, set the
; registers to return values that a DOS Int16h never would, and then
; return from this interrupt back to the TSR initialization routine.
;
xchg bx,cx ;Exchange regs. (DOS Int16h wouldn't do this)
xchg ax,dx ; " " "
;
pop ds ;Restore regs.
iret ;Return from Int to TSR Initialize routine.
;
Exit16:
pop ds ;Restore all registers
ASSUME DS:NOTHING ;v0.01
;
; Chain to prior Interrupt 16h handler routine:
jmp CS:oldint16
;
NewInt16 ENDP ;v0.01
;*************************************************************************
PAGE
;*************************************************************************
NewInt28 PROC FAR ;v0.01
;
pushf ;Call prior handler.
cli
call CS:oldint28
;
; Determine if this TSR's HotKey has been flagged as pressed:
cmp CS:hotkeyflag,1 ;Has HotKey been pressed?
jne QuickExit ;Exit if not.
;
cmp CS:bellgate,1 ;Is gate closed?
je QuickExit ;If so, exit.
mov CS:bellgate,1 ;Else close gate and proceed.
;
CLI ;DISABLE INTERRUPTS
; If you are here, then HotKey has been pressed.
push ax ;Entry for New Int. Handler.
push bx ;Save all registers.
push cx
push dx
push si
push di
push bp
push ds
push es
;
push CS
pop DS
ASSUME DS:CodeSeg ;v0.01
;
;
; Make sure InDOS flag is no greater than 1. The InDOS flag equals
; the number of DOS calls currently active. If we want to be sure
; that we do not disrupt DOS by reentry in our TSR user routine,
; we have to be sure that the present Int28 has occurred while
; only 1-deep into DOS calls (as it is when DOS is TRULY idling):
les bx,indosptr ;ES:bx points to InDOS flag.
cmp BYTE PTR ES:[bx],1 ;Is InDOS flag above 1?
ja Exit28 ;Exit if InDOS > 1.
;
; DOS is known to be idling at this point.
; At this point, HotKey is known to have been pressed. Now we will
; check to be sure that no time-critical hardware interrupt handling
; is underway. We do this by querying the Intel 8259A Programmable
; Interrupt Controller (PIC) chip's In Service Register (ISR) and
; testing it to see that it is zero (i.e., nothing being serviced
; except Int09 (PIC's IRQ1) ):
HotKeyPressed2:
mov al,ISRREQ ;al=PIC's OCW3 to ask for ISR Register.
out PICPORT,al ;Tell PIC to get ISR ready for reading.
jmp Dally2 ;Give PIC time to make ISR available.
Dally2: in al,PICPORT ;Fetch the ISR Register from PIC.
;
; Also, don't trigger the TSR if time-critical Disk access is underway:
or al,diskflag ;al = ISR | diskflag. (| => Logical OR).
jnz Exit28 ;If al not zero, try again later.
;
; Also, don't trigger the TSR if a PrtScrn is in progress:
; (Is this really necessary? I don't think TSR will trigger during PrtSc)
les bx,prtscrn ;ES:bx = pointer to PrtScrn busy flag.
cmp BYTE PTR es:[bx],1 ;Is PrtScrn in progress?
je Exit28 ;If so, Exit w/o triggering TSR.
;
STI ;ENABLE OTHER INTERRUPTS.
;
HotKeyFlagSet:
; Here, HotKey is flagged as pressed and DOS is idling (since we are
; servicing Int28h) and no hardware interrupts are being handled.
; Also, no Print Screen or Disk access is underway.
; DOS Int21h Functions above 0Ch can be accessed if required in your
; TSR routine:
;
call ROUTINE ;Call TSR routine; DOSOK & No Hardware
;interrupts being serviced.
mov CS:hotkeyflag,0 ;Clear HotKey Flag.
;
Exit28:
pop es ;Restore all registers
pop ds
ASSUME ds:NOTHING
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov CS:bellgate,0
;
QuickExit:
; Return from this Keyboard Interrupt 28h handler routine:
iret
;
NewInt28 ENDP ;v0.01
;*************************************************************************
; -END OF TSR's RESIDENT CODE-
; Only the code above will remain locked in memory
; after the initialization performed below.
;*************************************************************************
SUBTTL TSR BOOSTER (Initialization)
PAGE
;*************************************************************************
; BEGINNING OF TSR's INITIALIZATION CODE (THE "BOOSTER"):
; The following code is protected in RAM *ONLY* during initialization
; of the TSR that occurs when the TSR name is first invoked
; at the DOS command level. All the following code is abandonned
; unprotected in RAM after the Terminate-and-Stay-Resident (TSR)
; call to Function 31h of DOS Interrupt 21h below. This
; is allowed to happen because the code's work is complete at
; that point. The code will be overwritten as the memory which
; it temporarily occupied is needed by DOS for other purposes.
;
; I have seen this following section of code colorfully called
; the TSR "Booster". This is quite appropriate since the code
; sits here, strapped to the very end of the TSR, and it is of
; use only during the "blastoff" (initialization) of the TSR, when
; it is used to put the TSR into "orbit" (residency), and after
; which it is "jettisoned" (abandonned unprotected in memory) by
; the DOS TSR call, Int 21h, Fcn 31h.
;
TSRinit PROC NEAR ;v0.01
EndDump EQU $ ;Roy Silvernail - Keep TASM 1.0 happy
;when computing # resident paragraphs.
;
; Get DOS Version Number:
mov ah,30h ;Fcn 30h = Get DOS Version
int 21h ;DOS Version = al.ah
;
; If this is DOS v.1.x, this TSR cannot work, so go print message
; and exit without installing:
cmp al,1 ;Is this DOS Version 1.x?
ja DOSverOK ;If not, DOS version is OK.
push bx ;A "push" for the "pop" at DOSver1 label.
jmp DOSver1 ;If so, TSR won't work so exit.
;
DOSverOK:
; If here, DOS version is 2.0 or later. TSR can work, so proceed.
;
; Check for prior installation of this TSR:
;
mov ax,TSRsigA ;Prime registers for our
mov bx,TSRsigB ;Int16h handler's check
mov cx,TSRsigC ;for prior installation
mov dx,TSRsigD ;thru TSR signature words.
;
Int 16h ;Check prior installation.
;
cmp ax,TSRsigD ;Was TSR signature detected?
jne Install ;If not, Install it.
cmp bx,TSRsigC
jne Install
cmp cx,TSRsigB
jne Install
cmp dx,TSRsigA
jne Install
;
; If you are here, all four TSR signature words were detected and signalled,
; so the TSR is already installed.
; Announce the TSR's PRIOR Installation and exit:
mov dx,Offset PriorInstMsg ;DX points to message.
mov ah,09h ;DOS Fcn. 09h=Display String.
Int 21h ;Display String via DOS.
;
mov ax,4C00h ;Fcn 4C = DOS Terminate call
Int 21h ;Do it.
;
Install:
; If you are here, then DOS version is 2.+ and the TSR has not
; previously been installed.
;
; To conserve RAM usage, release from memory the copy of the DOS
; Environment passed to this TSR (this assumes, of course, that
; your Interrupt handler routine will not need to reference this
; de-allocated Environment) So, if you are going to write your
; TSR routine to reference the Environment, DON'T DEALLOCATE IT
; HERE.
;
;Get segment of Environment
;from 02Ch in the Program
;Segment Prefix (PSP).
;
mov ES,envseg ;ES=PSP's environ seg v0.01
mov ah,49h ;DOS Fcn 49h = Release Memory
int 21h ;Release it via DOS interrupt.
;
; In order to make the TSR's command name show under the "owner" column in
; the "MAPMEM" command of Kim Kokkonen's excellent TSR Mark/Release
; package, allocate a tiny 1-paragraph "Pseudo-Environment" here which
; contains nothing but the TSR name.
;
; Allocate the memory needed by the tiny 'Pseudo-Environment":
mov bx,1 ;Allocate one parag. (16bytes)
mov ah,48h ;and return allocation
int 21h ;segment in ax via DOS call.
;
mov ES,ax ;Pseudo-Env. Segment to ES.
mov si,OFFSET PseudoEnv ;si=source string OFFSET.
mov di,0 ;di=destination string OFFSET.
mov cx,ENVLNGTH ;cx=Bytes in Pseudo-Env.string.
cld ;Forward string move direction.
rep movsb ;Move Pseudo-Env. string @ DS:si to ES:di
;
; Set PSP's Environment segment pointer to point to tiny Pseudo-Environment.
mov envseg,ES
;
;*****************************************************************************
; NOW, capture all the required Interrupts:
;
; **** INT 09 ****
; Get Old Interrupt 09h Vector:
mov ax,3500H+HOOK09 ;Get old Int 9 vector v0.01
int 21h ;Int.Vector in ES:BX via DOS.
;
; Save Old Interrupt 09h Vector:
mov Word Ptr oldint09,bx ;Save Offset of Old Interrupt.
mov word ptr oldint09+2,ES ;save seg v0.01
;
; Install New Interrupt Vector to this TSR's "NewInt09:" Label:
mov ax,2500H+HOOK09 ;Set new Int 9 vector v0.01
mov dx,Offset NewInt09 ;dx=Offset of New Int Handler.
int 21h ;Set New Int via DOS.
;
; **** INT 13 ****
; Get Old Interrupt 13h Vector:
mov ax,3500H+HOOK13 ;Get old Int 13 vector
int 21h ;Int.Vector in ES:BX via DOS.
;
; Save Old Interrupt 13h Vector:
mov Word Ptr oldint13,bx ;Save Offset of Old Interrupt.
mov word ptr oldint13+2,ES ;save Segment.
;
; Install New Interrupt Vector to this TSR's "NewInt13:" Label:
mov ax,2500H+HOOK13 ;Set new Int 13 vector.
mov dx,Offset NewInt13 ;dx=Offset of New Int Handler.
int 21h ;Set New Int via DOS.
;
; **** INT 16 ****
; Get Old Interrupt 16h Vector:
mov ax,3500H+HOOK16 ;get old Int 16H vector v0.01
int 21h ;Int.Vector in ES:BX via DOS.
;
; Save Old Interrupt 16h Vector:
mov Word Ptr oldint16,bx ;Save Offset of Old Interrupt.
mov word ptr oldint16+2,ES ;save segment v0.01
;
; Install New Interrupt Vector to this TSR's "NewInt16:" Label:
mov ax,2500H+HOOK16 ;set new Int 16H vector v0.01
mov dx,Offset NewInt16 ;dx=Offset of New Int Handler.
int 21h ;Set New Int via DOS.
;
; **** INT 28 ****
; Get Old Interrupt 28h Vector:
mov ax,3500H+HOOK28 ;Get old Int 28H vector v0.01
int 21h ;Int.Vector in ES:BX via DOS.
;
; Save Old Interrupt 28h Vector:
mov Word Ptr oldint28,bx ;Save Offset of Old Interrupt.
mov word ptr oldint28+2,ES ;save segment v0.01
;
; Install New Interrupt Vector to this TSR's "NewInt28:" Label:
mov ax,2500H+HOOK28 ;set new Int 28H vector v0.01
mov dx,Offset NewInt28 ;dx=Offset of New Int Handler.
int 21h ;Set New Int via DOS.
;
;*****************************************************************************
; Get Pointer to InDOS flag ("DOS Busy" flag) and save it:
mov ah,34h ;DOS FCN=34h:Get InDOS Pointer.
int 21h ;Pointer in ES:BX
mov Word Ptr indosptr,bx ;Save Offset of InDOS flag.
mov Word Ptr indosptr+2,ES ;Save Segment of InDOS flag.
;
mov Word Ptr criterrptr+2,ES ;Also, Seg of CritErr flag.
push bx ;Save indosptr on stack for use below.
;
; Get DOS Version Number:
mov ah,30h ;Fcn 30h = Get DOS Version
int 21h ;DOS Version = al.ah
;
; If DOS version is 2.x, then DOS Critical Error flag is @ indosptr + 1.
; If DOS version is 3.x+, then DOS Critical Error flag is @ indosptr - 1.
; Determine DOS Version:
cmp al,2 ;Is it DOS Version 2.x?
je DOSver2 ;If yes, jump;
ja DOSver3 ;or, if later version, jump;
;else, it's DOS Version 1.x:
;
DOSver1: ;If here, DOS Version 1.x is being run:
mov dx,OFFSET BailOutMsg ;TBONES needs DOS 2.x or later.
mov ah,09h ;Say we're sorry, but NO GO
int 21h ;via DOS.
pop bx ;Clear stack.
int 20h ;Terminate without installing
;in only way DOS 1.x knows.
;
DOSver2: ;If here, DOS Version 2.x is being run:
pop bx ;Get indosptr from stack.
inc bx ;CritErr flag is @ indosptr+1.
mov Word Ptr criterrptr,bx ;Save CritErr Pointer.
jmp Announce ;Go announce TSR installed.
;
DOSver3: ;If here, DOS Version 3.+ is being run:
pop bx ;Get indosptr from stack.
dec bx ;CritErr flag is @ indosptr-1.
mov Word Ptr criterrptr,bx ;Save CritErr Pointer.
;
; Announce the TSR's Installation:
Announce:
mov dx,Offset InstallMsg ;DX points to message.
mov ah,09h ;DOS Fcn. 09h=Display String.
int 21h ;Display String via DOS.
;
; Lock resident code in memory via Terminate-and-Stay-Resident (TSR) DOS call:
;
;v0.11 DX requires size of resident code (in 16-byte paragraphs)
; This awkward construct is required to keep
; DOS Function 31h happy. Notice how we first compute
; the length of the TSR code in bytes [i.e., end of
; the TSR code (EndDump) minus start of the TSR code
; (0, our BeginDump)], round it up to the next whole paragraph ( + 0Fh),
; and then divide by 16 (SHR 4) to get the number of resident paragraphs:
;
mov dx,(EndDump-BeginDump+0Fh)/16
;Roy Silvernail discovered that the BeginDump and EndDump symbols
;were necessary to keep TASM 1.0 happy when computing # resident paragraphs
;in the above statement.
;
mov ah,31h ;DOS FCN 31h=TSR Call.
int 21h ;Go Resident via DOS TSR call.
;
PseudoEnv: DB ' ',0,0,1,0,'TSRBONES',0
ENVLNGTH EQU $-PseudoEnv
;
BailOutMsg:
db 0Dh,0Ah
db 'Sorry. TSRBONES needs DOS v.2+. You have v.1.x'
db 0Dh,0Ah,'$'
PriorInstMsg:
db 0Dh,0Ah
db 'TSRBONES IS *ALREADY* INSTALLED.'
InstallMsg:
db 0Dh,0Ah
db 'HotKey => Ctrl-Alt-B'
db 0Dh,0Ah
db 0Dh,0Ah
db 'TSRBONES Version 0.1'
db 0Dh,0Ah
db 'Copyright (C) 1990 by Robert Curtis Davis'
db 0Dh,0Ah,'$'
;
TSRinit ENDP ;v0.01
CodeSeg ends
end Entry
;***********************************************************************